import state from './state.js'
import utils from '@/common/utils/utils.js';

//写入二进制
function WriteBase(value, callback) {
	var deviceId = getApp().globalData.bleObj.deviceId;
	var serviceId = getApp().globalData.bleObj.serviceId;
	var characteristicId = getApp().globalData.bleObj.characteristicId;
	uni.writeBLECharacteristicValue({
		// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
		deviceId,
		// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
		serviceId,
		// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
		characteristicId,
		// 这里的value是ArrayBuffer类型
		value: value,
		success(res) {
			//console.log('writeBLECharacteristicValue', res);
			if (res.errCode == 0 || res.errno == 0) {
				callback(res);
			} else {
				console.log(res, '写入二进制success');
			}
		},
		fail(res) {
			console.log(res, '写入二进制fail');
		}
	})
}


/**
 * CRC计算函数
 * @param {Object} str
 */
function crc16Modbus(str) {
	var typedArray = new Uint8Array(str.trim().match(/[\da-f]{2}/gi).map(function(h) {
		return parseInt(h, 16)
	}));
	let crc = 0xFFFF;
	for (const byte of typedArray) {
		crc ^= byte;
		for (let j = 0; j < 8; j++) {
			crc = (crc & 0x0001) ? (crc >>> 1) ^ 0xA001 : crc >>> 1;
		}
	}
	const lowByte = (crc & 0xFF).toString(16).padStart(2, '0');
	const highByte = ((crc >> 8) & 0xFF).toString(16).padStart(2, '0');
	return `${lowByte}${highByte}`.toUpperCase();
}

function crc8Modbus(hexString) {
	// 将hex字符串分割成两个字符一组，并转换为字节数组
	let byteArray = [];
	for (let i = 0; i < hexString.length; i += 2) {
		byteArray.push(parseInt(hexString.substr(i, 2), 16));
	}

	// 初始化xor结果为第一个字节
	let xorResult = byteArray[0];
	// 对剩余的字节进行异或操作
	for (let i = 1; i < byteArray.length; i++) {
		xorResult ^= byteArray[i];
	}
	return xorResult.toString(16).padStart(2, '0');
}

/**
 * 发送指令 cmd 
 * @param {Object} cmd
 */
function sendCommand(cmd, callBackFun) {
	cmd = cmd.trim();
	var typedArray = new Uint8Array(cmd.match(/[\da-f]{2}/gi).map(function(h) {
		return parseInt(h, 16)
	}));
	// console.log('sendCmd', cmd);
	WriteBase(typedArray.buffer, (res) => {
		try {
			callBackFun(res)
		} catch (e) {
			console.log(e);
		}
	})
	// 判断指令长度
	const times = Math.ceil(cmd.length / 16);
	// for (var i = 0; i < times; i++) {
	// 	let sendCmd = ''
	// 	if (cmd.length > 16) {
	// 		sendCmd = cmd.substr(0, 16)
	// 		cmd = cmd.substr(16, cmd.length)
	// 	} else {
	// 		sendCmd = cmd.substr(0, cmd.length)
	// 	}
	// 	//console.log('发送数据', sendCmd);
	// 	var typedArray = new Uint8Array(sendCmd.match(/[\da-f]{2}/gi).map(function(h) {
	// 		return parseInt(h, 16)
	// 	}));
	// 	console.log('sendCmd', sendCmd);
	// 	WriteBase(typedArray.buffer, (res) => {
	// 		try {
	// 			callBackFun(res)
	// 		} catch (e) {
	// 			console.log(e);
	// 		}
	// 	})
	// }
}


//arrayBuffer转16进制字符串
function ab2hex(buffer) {
	const hexArr = Array.prototype.map.call(
		new Uint8Array(buffer),
		function(bit) {
			return ('00' + bit.toString(16)).slice(-2)
		}
	)
	return hexArr.join('');
}



/**
 * 组建 读取指令
 * @param {Object} item
 */
function buildReadCmd(item, N, X) {
	const Slave = '01'
	const fun = '03'
	let start = item.start;
	const len = item.len;
	let end = '0001';
	let cmd = Slave + fun;

	if (start === '0002') {
		end = (parseInt(N, 16)).toString(16).padStart(4, '0').toUpperCase();
		cmd = cmd + start + end;
	} else if (start === '2002') { //实时电流
		let startTen = parseInt('0002' || '0', 16)
		let nTen = parseInt(N || '0', 16)
		startTen = startTen + nTen;
		start = startTen.toString(16).padStart(4, '0').toUpperCase()
		cmd = cmd + start + end;
	} else if (start === '2005') { //MOS温度
		let startTen = parseInt('0005' || '0', 16)
		let nTen = parseInt(N || '0', 16)
		let xTen = parseInt(X || '0', 16) - 1
		startTen = startTen + nTen + xTen;
		start = startTen.toString(16).padStart(4, '0').toUpperCase()
		cmd = cmd + start + end;
	} else if (start === 'S005') {
		let startTen = parseInt('0005' || '0', 16)
		let nTen = parseInt(N || '0', 16)
		startTen = startTen + nTen;
		start = startTen.toString(16).padStart(4, '0').toUpperCase()
		cmd = cmd + start + end;
	} else if (start === '1005') { //电芯温度
		let startTen = parseInt('0005' || '0', 16)
		let nTen = parseInt(N || '0', 16) + 1
		let xTen = parseInt(X || '0', 16) - 2
		startTen = startTen + nTen;
		start = startTen.toString(16).padStart(4, '0').toUpperCase()
		end = xTen.toString(16).padStart(4, '0').toUpperCase()
		cmd = cmd + start + end;
	} else {
		if (item.isN) {
			let startTen = parseInt(start || '0', 16)
			let nTen = parseInt(N || '0', 16)
			startTen = startTen + nTen;
			start = startTen.toString(16).padStart(4, '0').toUpperCase()
		}
		if (item.isX) {
			let startTen = parseInt(start || '0', 16)
			let xTen = parseInt(X || '0', 16)
			startTen = startTen + xTen;
			start = startTen.toString(16).padStart(4, '0').toUpperCase()
		}
		if (len > 2) {
			end = (len / 2).toString(16).padStart(4, '0').toUpperCase()
		}
		cmd = cmd + start + end;
	}
	cmd = cmd + crc16Modbus(cmd);
	return cmd
}

/**
 * @param {Object} item
 *  01 BMS地址
 *	10 功能码写
 *	00 5C 要写入的寄存器首地址
 *	00 01 要写入的寄存器的个数1个
 *	02 要写入的字节数据2个
 *	21 02 写入的具体字节设置充电过流保护33A延时2S
 * 	33 5D 前面9个字节CRC校验码
 * 
 */
function buildWriteCmd(item, N, X, val) {
	const Slave = '01'
	const fun = '10'

	let start = item.start;
	const len = item.len * 1;
	let end = '0001';
	let cmd = Slave + fun;
	if (item.isN) {
		let startTen = parseInt(start || '0', 16)
		let nTen = parseInt(N || '0', 16)
		startTen = startTen + nTen;
		start = startTen.toString(16).padStart(4, '0').toUpperCase()
	}
	if (item.isX) {
		let startTen = parseInt(start || '0', 16)
		let xTen = parseInt(X || '0', 16)
		startTen = startTen + xTen;
		start = startTen.toString(16).padStart(4, '0').toUpperCase()
	}
	if (len > 2) {
		end = (len / 2).toString(16).padStart(4, '0').toUpperCase() + (len).toString(16).padStart(2, '0').toUpperCase()
	} else {
		end = end + (len).toString(16).padStart(2, '0').toUpperCase()
	}
	cmd = cmd + start + end + val.toUpperCase();
	cmd = cmd + crc16Modbus(cmd);
	return cmd
}

function bufferToHex(num) {
	let buffer = new ArrayBuffer(2);
	let view = new DataView(buffer);
	view.setUint16(0, num, false); // 大端模式
	let bytes = new Uint8Array(buffer);
	let hex = Array.from(bytes)
		.map(byte => byte.toString(16).padStart(2, '0'))
		.join('')
		.toUpperCase();
	return hex;
}
//解包
/**
 * 
 * 0103
 * C2
 * 0014,0006,0CBB,0CB9,0CB7,0CB8,0CB9,0CB9,0CBA,0CB9,0CB7,0CB9,0CBA,0CB6,0CB7,0CB7,0CB7,0CB6,0CB6,0CB4,0CB7,0CB4
 * 0000 负为放电电流,正为充电电流
 * 0030	State1
 * 0000	 State2
 * 0000	 State3
 * 0039,0039,0039,0039 电芯温度
 * 003B	MOS温度
 * 003D	环境温度
 * 0000	均衡状态1
 * 0000	均衡状态2
 * 0D14	版本
 * 1004	状态
 * 002C	告警状态
 * 004F	电量SOC
 * 0064	电量SOH
 * 0000	循环次数
 * 00019A28	电池包设计容量
 * 00019A28	当前电池满容量
 * 0001392C	电池剩余容量
 * FFFF	放电剩余时间	min
 * FFFF	充电剩余时间	min
 * 0016	当前充电间隔	h
 * 0016	最长充电间隔	h
 * 196F	电池总电压	10mV
 * 0CBA	电池包最高电压	 mV
 * 0CB3	电池包最低电压
 * 0003	 MOS控制
 * 0000	加热控制
 * 020D	最大允许充电电流	 10mA
 * 1C20	标准充电电压
 * 0000	当前湿度
 * 0000	GPS通讯模块电源控制
 * 2503 1209 5728 实时时钟RTC
 * 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 电池包编码
 * 0C49 3E50 4A1A D5C0 A2BC 8BC4 33AD F70A A3B4 E980 C9E8 78FD 7BFD 2DC6 55B4 F5A5 
 * 000E 电流检测电阻阻值
 * 6902	充电过流保护 充电过流保护延时
 * A509	电芯过压保护，过压保护延时
 * 2009	电芯过放保护 过放保护延时
 * 1932	过压滞后电压 过放滞后电压
 * 0101	电芯过压恢复延时 电芯过放恢复延时
 * 010C	放电过流2保护电压 放电过流2延时
 * 231E	放电高温保护 放电高温保护恢复
 * 000A	放电低低温保护 放电低温保护恢复
 * 1914	充电高温保护	充电高温保护恢复
 * 141E	充电低温保护 充电低温保护恢复
 * 1B0A	均衡开启电压 均衡开启压差
 * B402	放电过流1保护 放电过流1延时
 * 010B	放电短路保护 放电短路保护延时
 * 2823	环境高温保护 环境高温保护恢复
 * 0A0F	环境低温保护 环境低温保护恢复
 * 1C48	总压过压保护
 * 1A90	总压过压保护恢复
 * 11F8	总压过放保护
 * 15E0	总压过放恢复
 * 0A0A	总压过压保护延时 总压过放保护延时
 * 0101	总过压恢复延时 总过放恢复延时
 * 554B	 MOS高温保护	MOS高温恢复
 * 0500	 MOS高温保护延时 ，保留
 * 1AF4 00C8 0A00  充满保护(3个条件都达到) 1：总压高于  2充电电流低于 3 延时时间，保留
 * 1E28	加热/风扇开启温度	加热/风扇恢复温度
 * 01FF	使能设置
 * 0000	总压过压告警电压
 * 0000	总压过放告警电压
 * 027B
 * 
 * 
 * 0103
 * 3E 
 * 1AF4 00C8 0A00 充满保护(3个条件都达到) 1：总压高于  2充电电流低于 3 延时时间，保留
 * 1E28 加热/风扇开启温度	加热/风扇恢复温度
 * 01FF 使能设置
 * 0000	总压过压告警电压
 * 0000	总压过放告警电压
 * 0000	电芯过压告警电压	芯过放告警电压
 * 0000	充电过流告警电流
 * 0000	充电高温告警温度 充电低温告警温度
 * 0000	放电高温告警温度 放电低温告警温度
 * 826E	MOS过温告警温度	MOS过温告警恢复温度
 * 0000	电芯不均衡告警压差
 * 0000	不均衡告警恢复压差
 * 0000	环境高温告警，环境低温告警
 * 0A00	SOC低告警
 * 003B	最高电芯温度
 * 003B	最低电芯温度
 * 0000	温差
 * 0000	温差保护值
 * 0000	温差告警值
 * 0000	压差保护值
 * 0000	压差告警值
 * 0000	充电限流功能
 * 0414	掉电电压 掉电电流
 * 000A	掉电延时
 * 0100	每月自放电率，保留
 * 5A00
 * 0960
 * 0014
 * 0100	通讯地址，保留
 * D95D
 * 
 * @param {Object} str
 * @param {Object} item
 */
function solutionData(str, items, nValue, xValue, cmd) {
	let size = parseInt(str.substr(4, 2) || '0', 16);
	str = str.substr(6, size * 2)
	let xTen = parseInt(xValue || '0', 16)
	let nTen = parseInt(nValue || '0', 16)
	let iStart = 0,
		iLen = items.length
	if (cmd === '010300000076C42C') {
		iStart = 0;
		iLen = 42;
	} else {
		iStart = 43;
	}
	for (var i = iStart; i < iLen; i++) {
		let item = items[i]
		if (!item) {
			break;
		}
		let start = item.start
		let startTen = parseInt(start || '0', 16);
		let len = item.len * 2;
		if (item.start === '0002') {
			startTen = parseInt('0002' || '0', 16);
			len = len * (nTen)
		}
		if (item.start === '1002') {
			startTen = parseInt('0002' || '0', 16);
		}
		if (item.start === '1005') {
			startTen = parseInt('0005' || '0', 16) + 1;
			len = len * (xTen - 2)
		}
		if (item.start === '2005') {
			startTen = parseInt('0005' || '0', 16) - 1;
		}
		if (item.isN) {
			startTen = startTen + nTen;
		}
		if (item.isX) {
			startTen = startTen + xTen;
		}
		if (cmd !== '010300000076C42C') {
			startTen = startTen - xTen - nTen - parseInt('005C', 16);
		}
		let val = str.substr(startTen * 4, len);
		item.value = setItemValue(val, item)
		if (item.start === '000A') {
			//保存报警信息到本地
			let name = getApp().globalData.bleObj.name
			utils.readListWithFilterExpire(name + "PROTECT").then(saveArr => {
				for (var m = 0; m < item.value.length; m++) {
					let n = item.value[m]
					if (n.value > 0) {
						let it = {
							serialNumber: name,
							createTime: utils.parseTime(new Date()),
							alertName: n.desc[0]
						}
						saveArr.push(it)
						if (saveArr.length > 5) {
							saveArr.splice(0, 1)
						}
					}
				}
				utils.saveListWithExpire(name + "PROTECT", saveArr, 172800)
			})

		}
	}
}

function setItemValue(val, item) {
	var result = null;
	var start = item.start;
	let type = item.type; //type: 0 字符串 1 数组 -1 bit数据

	if (type < 0) {
		result = [];
		var v = hexToBitsFast(val);
		var vArray = v.split('').reverse();
		result = vArray
		if (start === '0003') {
			result = state.getState1(vArray.join(''))
		}
		if (start === '0004') {
			result = state.getState2(vArray.join(''))
		}
		if (start === 'S005') { //State3
			result = state.getState3(vArray.join(''))
		}
		if (start === '0009') { //状态
			result = state.getState(vArray.join(''))
		}
		if (start === '000A') { //告警状态
			result = state.getALARMState(vArray.join(''))
		}
		if (start === '0060') {
			result = state.getSettingState(vArray.join(''))
		}
	}
	if (type === 0) {
		result = parseInt(val || '0', 16)
		switch (start) {
			case '2005':
			case '0005':
				result = result - 40;
				break;
			case '1002':
				//判断当前是否在充电
				if (result > 0x7FFF) {
					result = result - 0x10000;
				}
				result = (result / 100).toFixed(2);
				break;
			case '0018':
				result = (result / 100).toFixed(2);
				break;
			case '0067':
			case '006A':
				result = []
				let max = parseInt(val.substr(0, 2) || '0', 16)
				let min = parseInt(val.substr(2, 2) || '0', 16)
				if (start === '0067') {
					max = max - 40
					min = min - 40
				}
				if (start === '006A') {
					max = max + 30
					min = min - 40
				}
				result = [max, min]
				break;
			case '000E':
			case '0010':
			case '0012':
			case '0019':
			case '001A':
				result = parseInt(val || '0', 16) / 1000
				break;
			case '0054':
			case '0056':
			case '0061':
			case '0062':
				result = parseInt(val || '0', 16) / 100
				break;
		}
	}
	if (type === 1) {
		result = []
		const arr = splitBySize(val, 4);
		for (var i = 0; i < arr.length; i++) {
			let t = arr[i]
			result.push(parseInt(t, 16))
		}
		if (start === '1005') {
			for (var i = 0; i < result.length; i++) {
				let t = result[i]
				t = t - 40
				result[i] = t
			}
		}
		if (start === '0002') {
			for (var i = 0; i < result.length; i++) {
				let t = result[i]
				t = t / 1000
				result[i] = t
			}
		}
	}

	if (type === 2) {
		result = []
		const arr = splitBySize(val, 2);
		for (var i = 0; i < arr.length; i++) {
			let t = arr[i]
			result.push(parseInt(t, 16))
		}
		//计算
		switch (start) {
			case '004B':
				result[0] = result[0] + 30
				result[1] = result[1] + 30
				break;
			case '004C':
				result[0] = result[0] - 40
				result[1] = result[1] - 40
				break;
			case '004D':
				//console.log('val, 2val, 2val, 2',val);
				result[0] = result[0] + 30
				result[1] = result[1] + 30
				break;
			case '004E':
				result[0] = result[0] - 40
				result[1] = result[1] - 40
				break;
		}
	}

	return result ? result : 0;
}


const hexMap = {
	'0': '0000',
	'1': '0001',
	'2': '0010',
	'3': '0011',
	'4': '0100',
	'5': '0101',
	'6': '0110',
	'7': '0111',
	'8': '1000',
	'9': '1001',
	'a': '1010',
	'b': '1011',
	'c': '1100',
	'd': '1101',
	'e': '1110',
	'f': '1111'
};

/**
 * @param {Object} hexStr
 * 
 * 
 */
function hexToBitsFast(hexStr) {
	return hexStr.toLowerCase()
		.split('')
		.map(c => hexMap[c] || '0000')
		.join('');
}

function dd(val) {
	var v = hexToBitsFast(val);
	console.log('vvvvvvvv', v);
	var vArray = v.split('').reverse();
	console.log(vArray);
	console.log('==============');

	v = parseInt("0x" + val).toString(2);
	vArray = v.split('').reverse();
	console.log('vvvvvvvv', v);
	console.log(vArray);
}


function splitBySize(str, size) {
	const arr = [];
	for (let i = 0; i < str.length; i += size) {
		arr.push(str.slice(i, i + size));
	}
	return arr;
}


export default {
	WriteBase: WriteBase,
	crc16Modbus: crc16Modbus,
	crc8Modbus: crc8Modbus,
	sendCommand: sendCommand,
	solutionData: solutionData,
	buildReadCmd: buildReadCmd,
	buildWriteCmd: buildWriteCmd,
}